<?php
require_once( 'Classes/Xml/ObjectArrayIterator.php' );

class XmlElement extends ObjectArrayIterator {
	
	// TODO: Doesn't handle content appearing after the tags, only before.

	var $sName;
	var $sContent;
	var $aAttributes;
	var $bContentIsCDATA;
	var $bContentIsXml;

	function XmlElement( $sName, $sContent = '', $bContentIsCDATA = false, $bContentIsXml = false ) {

		$this->ObjectArrayIterator();
		$this->aAttributes     = array();
		$this->sName           = strtoupper( $sName );
		$this->SetContent( $sContent, $bContentIsCDATA, $bContentIsXml );
		$this->RewindElementIterator();
	}
		
	function SetContent( $sContent, $bContentIsCDATA = false, $bContentIsXml = false ) {
		
		if ( ! is_string( $sContent ) && ! $sContent == null ) {
			return false;	
		}
		
		$this->sContent        = $sContent;
		$this->bContentIsCDATA = $bContentIsCDATA;
		$this->bContentIsXml   = $bContentIsXml;
		if ( $bContentIsCDATA && strpos( $sContent, ']]>' ) !== false ) {
			die( "Element=$sName, CDATA content cannot contain ']]>'" );	
		}
		return true;
	}
	
	function AddAttribute( $sName, $sValue ) {
		$sName = strtoupper( $sName );
		if     ( strtoupper( $sValue ) === 'TRUE'  ) $this->aAttributes[ $sName ] = true;
		elseif ( strtoupper( $sValue ) === 'FALSE' ) $this->aAttributes[ $sName ] = false;
		else	                                     $this->aAttributes[ $sName ] = $sValue;
	}

	function AddAttributes( $aAttributes ) {
		if ( ! is_array( $aAttributes ) ) {
			return false;
		}
		
		foreach( $aAttributes as $sName=>$sValue ) {
			$this->AddAttribute( $sName, $sValue );
		}
		return true;
	}

	function GetAllAttributesAsAssociativeArray() {
		return $this->aAttributes;
	}

	function GetName() {
		return $this->sName;	
	}
	
	function GetAttribute( $sName ) {
		$sName = strtoupper( $sName );
		if ( array_key_exists( $sName, $this->aAttributes ) ) {
			return $this->aAttributes[ $sName ];	
		}
		return null;
	}

	function _ReplaceXmlEntities( $sString ) {
	   return str_replace ( array ( '&', '"', "'", '<', '>', '?' ), array ( '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;', '&apos;' ), $sString );
	}

	function GetContent( $iIndentationLevel = 0 ) {
		
		if ( $this->bContentIsXml ) {
			return $this->_GetIndent( $iIndentationLevel + 1 ) . $this->sContent;
		} elseif ( $this->bContentIsCDATA ) {
			return '<![CDATA['. $this->sContent . ']]>';
		} else {
			return $this->_ReplaceXmlEntities( $this->sContent );
		}
	}

	function _GetAttributesAsString() {
		$sAttributeString = '';
		foreach ( $this->aAttributes as $sThisAttributeName => $sThisAttributeValue ) {
			if     ( $sThisAttributeValue === true  ) $xThisAttributeValue = 'TRUE';
			elseif ( $sThisAttributeValue === false ) $xThisAttributeValue = 'FALSE';
			else                                      $xThisAttributeValue = $sThisAttributeValue;
			$sAttributeString .= ' ' . strtolower( $sThisAttributeName ) . '="'. $xThisAttributeValue .'"';
		}
		return $sAttributeString;
	}

	function HasSomeAttributes() {
		return ! empty( $this->aAttributes );
	}

	function HasStructure() {
		return $this->HasSomeElements() || $this->HasSomeAttributes();
	}

	function HasContent() {
		return ! empty( $this->sContent );	
	}

	function _GetIndent( $iIndentationLevel ) {
		return "\r\n" . str_repeat( ' ', $iIndentationLevel * 2 );
	}

	function Generate( $iIndentationLevel = 0 ) {

		$sTagStart = $this->_GetIndent( $iIndentationLevel ) . '<' . $this->GetName() . $this->_GetAttributesAsString();

		if ( ! $this->HasContent() && ! $this->HasSomeElements() ) {
			return $sTagStart  . ' />';
		}
		
		$sXmlText = $sTagStart . '>' . $this->GetContent( $iIndentationLevel );

		$this->RewindElementIterator();
		while( $this->HasAnotherElement() ) {
			$oThisElement = $this->GetNextElement();
			$sXmlText .= $oThisElement->Generate( $iIndentationLevel + 1 );	
		}
		
		if ( ! $this->HasContent() ) {
			$sXmlText .= $this->_GetIndent( $iIndentationLevel );
		}
		$sXmlText .=  '</' . $this->GetName() . '>';

		return $sXmlText;	
	}
}
?>
